package com.ponhu.ea2.goodsCenter.provider.biz.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ponhu.ea2.annotations.EnableColumnChangeLog;
import com.ponhu.ea2.annotations.OperationRecordId;
import com.ponhu.ea2.dto.*;
import com.ponhu.ea2.entity.Inventory;
import com.ponhu.ea2.entity.OperationRecordLogs;
import com.ponhu.ea2.goodsCenter.provider.biz.OperationRecordLogsCoreService;
import com.ponhu.ea2.goodsCenter.provider.service.OperationRecordLogsService;
import com.ponhu.ea2.goodsCenter.provider.utils.CommonUtils;
import com.ponhu.ea2.goodsCenter.provider.utils.ProBeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.function.Function;

@Slf4j
@Service
public class OperationRecordLogsCoreServiceImpl implements OperationRecordLogsCoreService {

    @Autowired
    private OperationRecordLogsService operationRecordLogsService;

    /**
     * 表字段变动操作日志记录
     *
     * @param tableColumnsChangeDto
     * @param <T>
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public <T> boolean addTableColumnsChangeOperationRecordLogs(LogsForTableColumnsChangeDto<T> tableColumnsChangeDto) {
        Class<T> oldObjClass = (Class<T>) tableColumnsChangeDto.getOldObj().getClass();
        Class<T> newObjClass = (Class<T>) tableColumnsChangeDto.getNewObj().getClass();

        Field[] oldFields = oldObjClass.getDeclaredFields();
        Field[] newFields = newObjClass.getDeclaredFields();

        List<OperationRecordContentDto> changeContentDtoList = new ArrayList<>();
        for (Field i : oldFields) {
            try {
                EnableColumnChangeLog annotation = i.getAnnotation(EnableColumnChangeLog.class);
                if (annotation != null) {
                    i.setAccessible(true);

                    OperationRecordContentDto contentDto = new OperationRecordContentDto();
                    contentDto.setColumnDesc(annotation.columnDesc());

                    //获取旧值
                    Object oldObj = ObjectUtils.defaultIfNull(i.get(tableColumnsChangeDto.getOldObj()), "");
                    String oldValue = CommonUtils.convertObjectValue(i.get(tableColumnsChangeDto.getOldObj()));
                    contentDto.setOldValue(oldValue);

                    Field newField = Arrays.stream(newFields).filter(n -> {
                        n.setAccessible(true);
                        return n.getName().equals(i.getName());
                    }).findFirst().get();

                    //获取新值
                    Object newObj = ObjectUtils.defaultIfNull(newField.get(tableColumnsChangeDto.getNewObj()), "");
                    String newValue = CommonUtils.convertObjectValue(newField.get(tableColumnsChangeDto.getNewObj()));
                    contentDto.setNewValue(newValue);

                    //如果不同添加记录
                    if (!CommonUtils.deepEquals(oldObj, newObj)) {
                        changeContentDtoList.add(contentDto);
                    }
                }
            } catch (IllegalAccessException e) {
                //nothing to do
            }
        }

        if (CollectionUtils.isEmpty(changeContentDtoList)) {
            return false;
        }

        OperationRecordDto changeDto = new OperationRecordDto();
        BeanUtils.copyProperties(tableColumnsChangeDto, changeDto);

        changeDto.setChangeContentDtoList(changeContentDtoList);
        return this.addTableColumnChangeLog(changeDto);
    }

    /**
     * 文本添加类型操作日志记录
     *
     * @param textAddDto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean addTextAddOperationRecordLogs(LogsForTextAddDto textAddDto) {
        OperationRecordLogs operationRecordLogs = new OperationRecordLogs();
        BeanUtils.copyProperties(textAddDto, operationRecordLogs);

        boolean res = operationRecordLogsService.save(operationRecordLogs);
        return res;
    }

    /**
     * 表字段变动操作日志记录
     *
     * @param changeDto
     * @return
     */
    private boolean addTableColumnChangeLog(OperationRecordDto changeDto) {
        OperationRecordLogs operationRecordLogs = new OperationRecordLogs();
        BeanUtils.copyProperties(changeDto, operationRecordLogs);
        operationRecordLogs.setBusinessTable(changeDto.getBusinessTable());
        if (CollectionUtils.isEmpty(changeDto.getChangeContentDtoList())) {
            return false;
        }
        operationRecordLogs.setContent(JSONArray.toJSONString(changeDto.getChangeContentDtoList()));

        return operationRecordLogsService.save(operationRecordLogs);

    }

    @Override
    public <T> void operationRecordLogs(CompletableFuture<T> oldFuture,
                                        T newT, String typeMsg, OperatorDto operatorDto) {
        oldFuture.join();
        oldFuture.thenAcceptAsync(oldT -> {
            try {
                Field idField = Arrays.asList(oldT.getClass().getDeclaredFields()).stream().filter(field -> {
                    field.setAccessible(true);
                    return ObjectUtils.isNotEmpty(field.getAnnotation(OperationRecordId.class));
                }).findFirst().get();
                OperationRecordId annotation = idField.getAnnotation(OperationRecordId.class);
                LogsForTableColumnsChangeDto<T> changeDto = new LogsForTableColumnsChangeDto()
                        .setOldObj(oldT)
                        .setNewObj(newT)
                        .setBusinessTable(annotation.businessTable())
                        .setRecordId((Long) idField.get(oldT))
                        .setOperatorId(operatorDto.getOperatorId())
                        .setOperator(operatorDto.getOperatorName());
                addTableColumnsChangeOperationRecordLogs(changeDto);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("{} ===>> 原值={}，新值={} ===>> 操作人=[ID={}，NAME={}] ===>> Error={}",
                        typeMsg, JSON.toJSONString(oldT), JSON.toJSONString(newT),
                        operatorDto.getOperatorId(), operatorDto.getOperatorName(), e.getMessage());
            }
        });
    }

}
